using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using NEM;
using System.Net;
using System.Windows.Forms;
using Newtonsoft.Json;
using Microsoft.Win32;
using NEM.Networking_Classes;
namespace NEM.Networking_Classes
{
    /// <summary>
    /// This Class will get all the available network connection Objects And populate a List of [NetworkConnection] classes.
    /// </summary>
    [Serializable]
    public class NetworkConnections
    {
        #region Private Variables / Constants

        #endregion

        #region Constructors
        public NetworkConnections()
        {
            GetConnectionsUpdate();
        }
        #endregion

        #region Properties

        private List<NetworkConnection> _NetworkConnections = new List<NetworkConnection>();
        /// <summary>
        /// List of the Connection that where found on this System.
        /// </summary>
        /// <value>
        /// List of Connection found on the system.
        /// </value>
        [Category("Network Connections")]
        [DisplayName("Network Connection")]
        [Description("List of all the network connections to be used.")]
        public List<NetworkConnection> Connections
        {
            get { return _NetworkConnections; }
            set { _NetworkConnections = value; }
        }

        #endregion

        #region Methods
        /// <summary>
        /// Gets all the network connections and updates the List.
        /// </summary>
        /// <returns>Boolean used to indicate if process was successful.</returns>
        public bool GetConnectionsUpdate()
        {
            bool lvResult = true;
            bool lvAddConnection = true;

            ManagementClass lvManagmentClass = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection lvManObjects = lvManagmentClass.GetInstances();

            foreach (ManagementObject lvCurrentObj in lvManObjects)
            {
                try
                {

                    if (this._NetworkConnections.Where(lvConnection => lvConnection.Name == lvCurrentObj["Caption"]).Count() > 0)
                    {
                        //Exists Update
                        NetworkConnection lvUpdateItem = this._NetworkConnections.Where(lvConnection => lvConnection.Name == lvCurrentObj["Caption"]).FirstOrDefault();
                        lvUpdateItem.PopulateFromObj(lvCurrentObj);

                        //update in list.
                        this._NetworkConnections.Remove(this._NetworkConnections.Where(lvConnection => lvConnection.Name == lvCurrentObj["Caption"]).FirstOrDefault());
                        this._NetworkConnections.Add(lvUpdateItem);
                    }
                    else
                    {
                        //Check if we should add Item.
                        //Check in settings if all Connections or only IPEnabled Connections Should Show.
                        if (Globals.ApplicationSettings.OnlyIPEnabled)
                        {
                            if ((bool)lvCurrentObj["IPEnabled"])
                            {
                                lvAddConnection = true;
                            }
                            else
                            {
                                lvAddConnection = false;
                            }
                        }

                        //Check if we need to add this Connection
                        if (lvAddConnection)
                        {
                            //Create Temp NetworkConnection Info Class to be added to List.
                            NetworkConnection lvTempConnection = new NetworkConnection();
                            lvTempConnection.PopulateFromObj(lvCurrentObj);

                            //Add To the List.
                            _NetworkConnections.Add(lvTempConnection);
                        }
                    }


                }
                catch (Exception ex)
                {
                    lvResult = false;
                }
            }

            return lvResult;
        }

        #endregion

        #region Overrides
        public override string ToString()
        {
            return "Network Connections.";
        }
        #endregion
    }

    /// <summary>
    /// This class contains the Network connections information.
    /// </summary>
    [Serializable]
    public class NetworkConnection
    {
        #region Private Variables / Constants
        private ManagementObject _Connection = null;
        #endregion

        #region Constructors
        public NetworkConnection()
        {

        }
        #endregion

        #region Properties



        private string _Name = string.Empty;
        [Category("Network Connection Info")]
        [DisplayName("Network Connection Name")]
        [Description("Name of the Network Connection")]
        public string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        #region IP Settings
        private string _IPAddress =  string.Empty;
        [Category("IP Settings")]
        [DisplayName("IP Address")]
        [Description("IP Address")]
        public string IPAddress
        {
            get { return _IPAddress; }
            set { _IPAddress = value; }
        }

        private string _Subnet = string.Empty;
        [Category("IP Settings")]
        [DisplayName("Subnet")]
        [Description("Subnet")]
        public string Subnet
        {
            get { return _Subnet; }
            set { _Subnet = value; }
        }

        private string _Gateway = string.Empty;
        [Category("IP Settings")]
        [DisplayName("Gateway")]
        [Description("Gateway Address")]
        public string Gateway
        {
            get { return _Gateway; }
            set { _Gateway = value; }
        }

        private List<string> _DNSServers = new List<string>();
        [Category("IP Settings")]
        [DisplayName("DNS Servers")]
        [Description("List of DNS Servers")]
        public List<string> DnsServers
        {
            get { return _DNSServers; }
            set { _DNSServers = value; }
        }

        #endregion End of IP Settings


        private String _DNSHostName = string.Empty;
        [Category("DNS Information")]
        [DisplayName("DNS Host Name")]
        [Description("Host Name of the DNS Server if found.")]
        public String DNSHostName
        {
            get { return _DNSHostName; }
            set { _DNSHostName = value; }
        }

        #endregion

        #region Methods
        /// <summary>
        /// Populates properties from object.
        /// </summary>
        /// <param name="lvCurrentObj">The network connection object.</param>
        public void PopulateFromObj(ManagementObject lvCurrentObj)
        {
            _Connection = lvCurrentObj;

            try
            {
                _Name = lvCurrentObj["Caption"].ToString();
                _IPAddress = lvCurrentObj.GetProp("IPAddress");
                _Subnet = lvCurrentObj.GetProp("IPSubnet");
                _Gateway = lvCurrentObj.GetProp("DefaultIPGateway");
                _DNSServers = lvCurrentObj.GetPropList("DNSServerSearchOrder");
                _DNSHostName = lvCurrentObj["DNSHostName"].ToString();

            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// Sets the ip settings.
        /// </summary>
        /// <param name="pAddressInfo">The p address information.</param>
        /// <returns>Boolean to indicate if process was a success.</returns>
        public bool SetIPSettings(IPAddressInfo pAddressInfo)
        {
            bool lvResult = true;

            if (_Connection == null)
            {
                ManagementClass lvManagmentClass = new ManagementClass("Win32_NetworkAdapterConfiguration");
                ManagementObjectCollection lvManObjects = lvManagmentClass.GetInstances();

                foreach (ManagementObject lvCurrentObj in lvManObjects)
                {
                    try
                    {
                        if (lvCurrentObj["Caption"].ToString() == pAddressInfo.NetworkCard.Name)
                        {
                            _Connection = lvCurrentObj;
                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        lvResult = false;
                        MessageBox.Show(ex.Message);
                    }
                }
            }

            if (pAddressInfo.UseDHCP)
            {
                //Set DHCP enabled.
                try
                {
                    _Connection.InvokeMethod("SetDNSServerSearchOrder", new object[] { new string[0] });
                    _Connection.InvokeMethod("EnableDHCP", null);
                }
                catch (Exception ex)
                {
                    lvResult = false;
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                try
                {

                    #region Setup Registry
                    // workaround of windows bug (windows refused to apply static ip in network properties dialog)
                    var settingID = _Connection.GetPropertyValue("SettingID"); // adapter = the management object
                    using (var regKey = Registry.LocalMachine
                                       .OpenSubKey(@"SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\" + settingID, true))
                    {
                        regKey.SetValue("EnableDHCP", 0);
                        regKey.SetValue("IPAddress", pAddressInfo.IP);
                        regKey.SetValue("SubnetMask", pAddressInfo.Subnet);
                        regKey.SetValue("DefaultIPGateway", pAddressInfo.Gateway);
                        regKey.SetValue("NameServer", pAddressInfo.DnsServer.FirstOrDefault() == null ? "" : pAddressInfo.DnsServer.FirstOrDefault().ToString());
                    }
                    #endregion

                    #region Set Network Connection Settings
                    //Set IP Address Info
                    var val = _Connection.InvokeMethod("EnableStatic", new object[] {
                                                        new string[] { pAddressInfo.IP },
                                                        new string[] { pAddressInfo.Subnet } });

                    val = _Connection.InvokeMethod("SetGateways", new object[] {
                                                    new string[] { pAddressInfo.Gateway },
                                                    new UInt16[] { 1 } });

                    val = _Connection.InvokeMethod("SetDNSServerSearchOrder", new object[] { pAddressInfo.DnsServer.ToArray()  });
                    #endregion 
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    lvResult = false;
                    throw;
                }
            }

            return lvResult;
        }
        #endregion

        #region Overrides
        public override string ToString()
        {
            return _Name == string.Empty ? "Select Network Connection." :  _Name;
        }
        #endregion
    }

}


/// <summary>
/// This Class holds information for IP Change if needed for Network Profile.
/// </summary>
[Serializable]
public class IPAddressInfo
{
    #region Private Variables / Constants

    #endregion

    #region Constructors
    public IPAddressInfo()
    {

    }
    #endregion

    #region Properties
    private NetworkConnection _NetworkCard = new NetworkConnection();
    /// <summary>
    /// Gets or sets the network Connection.
    /// </summary>
    /// <value>
    /// The network Connection.
    /// </value>
    [TypeConverter(typeof(NetworkCardConverter))]
    [Category("Address Information")]
    [DisplayName("0 - Network Connection")]
    [Description("Connection used to Set IP Address Info on.")]
    public NetworkConnection NetworkCard
    {
        get { return _NetworkCard; }
        set { _NetworkCard = value; }
    }


    private string _IP = string.Empty;
    /// <summary>
    /// Gets or sets the IP Address.
    /// </summary>
    /// <value>
    /// The IP Address.
    /// </value>
    [Category("Address Information")]
    [DisplayName("2 - IP Address")]
    [Description("The IP Address to be used with this Proxy")]
    public string IP
    {
        get { return _IP; }
        set
        {
            if (isVlaidIP(value))
            {
                _IP = value;
            }
            else
            {
                MessageBox.Show("IP Address is Not Valid, did not Update value.");
            }
        }
    }

    private string _SubNet = string.Empty;
    /// <summary>
    /// Gets or sets the subnet IP.
    /// </summary>
    /// <value>
    /// The subnet IP.
    /// </value>
    [Category("Address Information ")]
    [DisplayName("3 - Subnet")]
    [Description("Subnet Address to be used with this proxy")]
    public string Subnet
    {
        get { return _SubNet; }
        set { _SubNet = value; }
    }

    private string _GateWay = string.Empty;
    /// <summary>
    /// Gets or sets the Default gateway IP.
    /// </summary>
    /// <value>
    /// The Default gateway IP.
    /// </value>
    [Category("Address Information ")]
    [DisplayName("4 -Gateway Address")]
    [Description("The Gateway Address used for this proxy")]
    public string Gateway
    {
        get { return _GateWay; }
        set
        {
            if (isVlaidIP(value))
            {
                _GateWay = value;
            }
            else
            {
                MessageBox.Show("Gateway IP Address is Not Valid, did not Update value.");
            }
        }
    }

    private List<string> _DNSServers = new List<string>();
    /// <summary>
    /// Gets or sets the DNS server.
    /// </summary>
    /// <value>
    /// The DNS server.
    /// </value>
    [Category("Address Information")]
    [DisplayName("DNS Server Address")]
    [Description("Address of the DNS Server")]
    [Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))]
    public List<string> DnsServer
    {
        get { return _DNSServers; }
        set { _DNSServers = value; }
    }

    private bool _UseDHCP = true;
    /// <summary>
    /// Gets or sets a value indicating whether to use DHCP or Static IP Address
    /// </summary>
    /// <value>
    ///   <c>true</c> use DHCP; otherwise, <c>false</c> use Static IP.
    /// </value>
    [Category("Address Information")]
    [DisplayName("1 - Use DHCP")]
    [Description("Should DHCP or Static IP address be used.")]
    public bool UseDHCP
    {
        get { return _UseDHCP; }
        set { _UseDHCP = value; }
    }
    #endregion

    #region Methods

    /// <summary>
    /// Determines whether IP address Passed is of Type IPV4 or IPV6 both Valid IP Address types.
    /// </summary>
    /// <param name="pIPAddress">The IP Address to Validate.</param>
    /// <returns>Returns a Boolean  true: Valid IP; false: Not a Valid IP Address</returns>
    public bool isVlaidIP(string pIPAddress)
    {
        bool lvResult = true;

        IPAddress address;
        if (IPAddress.TryParse(pIPAddress, out address))
        {
            switch (address.AddressFamily)
            {
                case System.Net.Sockets.AddressFamily.InterNetwork:
                    //IPv4
                    break;
                case System.Net.Sockets.AddressFamily.InterNetworkV6:
                    //IPv6
                    break;
                default:
                    //Unknown IP Type.
                    lvResult = false;

                    break;
            }
        }

        return lvResult;
    }

    internal bool Validate(out string pRetrunMessage)
    {
        bool lvResult = true;
        string lvReturnMessage = string.Empty;

        //Check if Network Connection has been Selected.
        if (NetworkCard == null)
        {
            lvReturnMessage = "IP Information missing network device.";
            lvResult = false;
        }

        //Do validation on other properties.
        if (lvResult)
        {
            if (!_UseDHCP)
            {
                if ((IP == string.Empty) || (Subnet == string.Empty) || (Gateway == string.Empty))
                {
                    lvResult = false;
                    lvReturnMessage = "Please Check the IP address information as it failed validation.";
                }

                if (lvResult)
                {
                    if (!Globals.isVlaidIP(IP))
                    {
                        lvResult = false;
                        pRetrunMessage = "Please check IP Address as it did not pass validation.";
                    }
                }
            }
        }


        pRetrunMessage = lvReturnMessage;
        return lvResult;
    }
    #endregion

    #region Overrides
    public override string ToString()
    {
        return IP != string.Empty ? IP : "Setup Network Address Settings";
    }
    #endregion


}

/*

[Provider("CIMWin32")]class Win32_NetworkAdapterConfiguration : CIM_Setting
{
  boolean  ArpAlwaysSourceRoute;
  boolean  ArpUseEtherSNAP;
  string   Caption;
  string   DatabasePath;
  boolean  DeadGWDetectEnabled;
  string   DefaultIPGateway[];
  uint8    DefaultTOS;
  uint8    DefaultTTL;
  string   Description;
  boolean  DHCPEnabled;
  datetime DHCPLeaseExpires;
  datetime DHCPLeaseObtained;
  string   DHCPServer;
  string   DNSDomain;
  string   DNSDomainSuffixSearchOrder[];
  boolean  DNSEnabledForWINSResolution;
  string   DNSHostName;
  string   DNSServerSearchOrder[];
  boolean  DomainDNSRegistrationEnabled;
  uint32   ForwardBufferMemory;
  boolean  FullDNSRegistrationEnabled;
  uint16   GatewayCostMetric[];
  uint8    IGMPLevel;
  uint32   Index;
  uint32   InterfaceIndex;
  string   IPAddress[];
  uint32   IPConnectionMetric;
  boolean  IPEnabled;
  boolean  IPFilterSecurityEnabled;
  boolean  IPPortSecurityEnabled;
  string   IPSecPermitIPProtocols[];
  string   IPSecPermitTCPPorts[];
  string   IPSecPermitUDPPorts[];
  string   IPSubnet[];
  boolean  IPUseZeroBroadcast;
  string   IPXAddress;
  boolean  IPXEnabled;
  uint32   IPXFrameType[];
  uint32   IPXMediaType;
  string   IPXNetworkNumber[];
  string   IPXVirtualNetNumber;
  uint32   KeepAliveInterval;
  uint32   KeepAliveTime;
  string   MACAddress;
  uint32   MTU;
  uint32   NumForwardPackets;
  boolean  PMTUBHDetectEnabled;
  boolean  PMTUDiscoveryEnabled;
  string   ServiceName;
  string   SettingID;
  uint32   TcpipNetbiosOptions;
  uint32   TcpMaxConnectRetransmissions;
  uint32   TcpMaxDataRetransmissions;
  uint32   TcpNumConnections;
  boolean  TcpUseRFC1122UrgentPointer;
  uint16   TcpWindowSize;
  boolean  WINSEnableLMHostsLookup;
  string   WINSHostLookupFile;
  string   WINSPrimaryServer;
  string   WINSScopeID;
  string   WINSSecondaryServer;
};
*/
